﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using NUnit.Framework;
using WB.Mvc.Forms;
using WB.Mvc.Forms.Widgets;

namespace WB.Forms.Tests
{
	public class FieldTestFixture
	{
		[TestFixture]
		public abstract class FieldTestFixtureBase
		{
			protected Field field;

			[SetUp]
			public void InitializeTest()
			{
				field = CreateField();
			}

			[Test]
			public void IsValid_By_Default()
			{
				Assert.IsTrue(field.IsValid);
			}

			protected abstract Field CreateField();
		}

		[TestFixture]
		public class SimpleInheritanceTestFixture
		{
			[Test]
			public void Label_Created_With_Default_Name_And_Value()
			{
				const string fieldName = "Some_Field";
				SimpleField field = new SimpleField(fieldName);

				Assert.AreEqual(XName.Get("label"), field.Label.Name);
				Assert.AreEqual("Some Field", field.Label.Value);
			}

			[Test]
			public void Has_Default_ErrorMessage()
			{
				SimpleField field = new SimpleField("field");

				Assert.IsNotNull(field.ErrorMessage, "Should not have null error message.");
				Assert.IsNotEmpty(field.ErrorMessage, "Should not have empty error message.");
			}

			[Test]
			public void ToXml_Returns_Three_Elements()
			{
				const string fieldName = "some_field";
				SimpleField field = new SimpleField(fieldName);

				XElement[] elements = field.ToXml();

				Assert.AreEqual(3, elements.Length);
			}

			[Test]
			public void ToXml_Returns_Label_And_Input_And_Span_Elements()
			{
				const string fieldName = "some_field";
				SimpleField field = new SimpleField(fieldName);

				XElement[] elements = field.ToXml();

				Assert.AreEqual("label", elements.First().Name.ToString());
				Assert.AreEqual("input", elements.ElementAt(1).Name.ToString());
				Assert.AreEqual("span", elements.Last().Name.ToString());
			}
		}

		[TestFixture]
		public class CharFieldTestFixture: FieldTestFixtureBase
		{
			protected override Field CreateField()
			{
				return new CharField("charField");
			}

			[Test]
			public void Empty_String_Is_Invalid()
			{
				field.Required = true;
				field.Value = string.Empty;
				field.Validate();

				Assert.IsFalse(field.IsValid);
			}

			[Test]
			public void IsRequired_By_Default()
			{
				Assert.IsTrue(field.Required);
			}
		}

		[TestFixture]
		public class BooleanFieldTestFixture : FieldTestFixtureBase
		{
			protected override Field CreateField()
			{
				return new BooleanField("bool");
			}

			[Test]
			public void IsValid_Is_True()
			{
				field.Value = "true";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "True";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "false";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "False";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "0";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "1";
				field.Validate();
				Assert.IsTrue(field.IsValid);

				field.Value = "abc";
				field.Validate();
				Assert.IsTrue(field.IsValid);
			}
		}

		[TestFixture]
		public class IntegerFieldTestFixture : FieldTestFixtureBase
		{
			protected override Field CreateField()
			{
				return new IntegerField("integer");
			}

			[Test]
			public void Positive_Number_Is_Valid()
			{
				field.Value = 1.ToString();
				field.Validate();

				Assert.IsTrue(field.IsValid);
			}

			[Test]
			public void Negative_Number_Is_Valid()
			{
				field.Value = (-1).ToString();
				field.Validate();

				Assert.IsTrue(field.IsValid);
			}

			[Test]
			public void Zero_Is_Valid()
			{
				field.Value = 0.ToString();
				field.Validate();

				Assert.IsTrue(field.IsValid);
			}

			[Test]
			public void Characters_Are_Invalid()
			{
				field.Value = "abcdef";
				field.Validate();

				Assert.IsFalse(field.IsValid);
			}

			[Test]
			public void Decimal_Is_Invalid()
			{
				field.Value = 1.2.ToString();
				field.Validate();

				Assert.IsFalse(field.IsValid);
			}
		}

		protected class SimpleField : Field
		{
			public SimpleField(string name) : base(name)
			{
			}

			/// <summary>
			/// Gets the widget used to render the input for this field.
			/// </summary>
			public override Widget GetWidget()
			{
				return new SimpleWidget();
			}
		}

		protected class SimpleWidget : Widget
		{
			public SimpleWidget() : base("simple")
			{
			}

			public override string ToHtml()
			{
				return "<input type='text' />";
			}
		}
	}
}
